package main

import (
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"
	"github.com/kataras/iris/sessions/sessiondb/badger"
	"github.com/kataras/iris/websocket"
)

type Site struct {
	Conf    *config
	Db      *MyDB
	Sesns   *sessions.Sessions
	App     *iris.Application
	Clients sync.Map
	Ws      *websocket.Server
}

func (site1 *Site) Init(cfgPathName string) error {
	//读入配置文件
	site1.Conf = readToml(cfgPathName)
	if site1.Conf == nil {
		return errors.New("Site Init: readToml error")
	}
	//连接数据库
	site1.Db = NewMyDB(site1.Conf.DbAddr, site1.Conf.DbUser, site1.Conf.DbPwd, site1.Conf.DbName)
	if site1.Db == nil {
		return errors.New("Site Init: database connect error")
	}
	//初始化数据库 users、history ，带条件：if not exists
	sqlInit := []string{`create table if not exists users(id SERIAL,name text unique PRIMARY KEY,md5pwd CHAR(32) not null,level int default 4,other text);`,
		`create table if not exists history(id SERIAL,name text not null,room text not null,msg text not null,time timestamp default NOW(),PRIMARY KEY(id,room));`,
		`comment on table users is '注册用户数据';`,
		`comment on table history is '聊天历史记录';`}
	site1.Db.ExecSqls(sqlInit)
	//初始化 iris.Application
	site1.App = iris.New()
	//设置 views
	site1.App.RegisterView(iris.HTML(site1.Conf.ViewDir, ".html"))
	//设置 static
	site1.App.StaticWeb("/static", site1.Conf.StaticDir)
	//初始化 sessions
	site1.Sesns = sessions.New(sessions.Config{Cookie: "sessionid"})
	db, err := badger.New(site1.Conf.SessionDir)
	if err != nil {
		return err
	}
	site1.Sesns.UseDatabase(db)

	return nil
}

func (site1 *Site) Close() {
	site1.Db.Close()
	site1.Sesns.DestroyAll()
}

//Global 运行于每个handler之前，验证登录状态
func (site1 *Site) Global(ctx iris.Context) {
	defer ctx.Next()
	if ctx.Path() == "/chat/serve" {
		log.Printf("Global Skip: %s\n", ctx.String())
		return
	}
	if strings.HasPrefix(ctx.Path(), "/static/") {
		log.Printf("Global Skip: %s\n", ctx.String())
		return
	}
	opt := iris.CookieHTTPOnly(false)
	s1 := site1.Sesns.Start(ctx)
	//log.Printf("SessionID:%s\n", ctx.GetCookie("sessionid"))
	v := s1.GetString("logined")
	if v == "" || v == "no" {
		if ctx.GetCookie("start") == "" {
			t := fmt.Sprintf("%d", time.Now().Unix())
			log.Printf("start:%s\n", t)
			s1.Set("start", t)
			s1.Set("logined", "no")
			ctx.SetCookieKV("addr", ctx.Request().RemoteAddr, opt)
			ctx.SetCookieKV("start", t, opt)
			ctx.SetCookieKV("logined", "no")
		}
	} else if v == "yes" {
		//check is logined
		ctx.SetCookieKV("logined", v)
		ctx.SetCookieKV("chatname", s1.GetString("chatname"))
	}
	log.Printf("Global: %s %s %s\n", ctx.Method(), ctx.Host(), ctx.Path())
}

//设置各种 handler，然后运行服务
func (site1 *Site) Run() {
	site1.App.UseGlobal(site1.Global)
	site1.setUsersHandlers()
	site1.setWsServer()
	site1.App.Get("/history/{roomName:string}/{pageNumber:long}", site1.showHistory)
	site1.App.Get("/history/{roomName:string}/s", site1.findHistory)
	site1.App.Any("/", func(ctx iris.Context) {
		ctx.StatusCode(iris.StatusTemporaryRedirect)
		ctx.Redirect("/user/")
	})

	site1.App.Run(iris.Addr(site1.Conf.WWWAddr))
}
func main() {
	site1 := new(Site)
	defer site1.Close()
	pathname, err := os.Executable()
	if err != nil {
		panic(err)
	}
	dir1 := filepath.Dir(pathname)
	site1.Init(filepath.Join(dir1, "conf.toml"))
	if err != nil {
		panic(err)
	}
	ioutil.WriteFile(filepath.Join(dir1, "static", "iris-ws.js"), websocket.ClientSource, 0644)
	site1.Run()
}
